#coding=utf-8

# establish connection

#import ADS1256
#import DAC8532
from tokenize import Double
import numpy as np
import os
import random
import json

def killport(port):
    command="kill -9 $(netstat -nlp | grep :"+str(port)+" | awk '{print $7}' | awk -F'/' '{{ print $1 }}')"
    os.system(command)
killport(9575)

import socket
localIp = socket.gethostbyname(socket.gethostname()) + ':9580'

defaultParams = {
    'trans':{
        'AGND': '2.5',	# given by the particular LDO 
        'drainV': '0.5',	# ref AGND
        'gateV_begin': '-0.8',	# ref AGND 
        'gateV_end': '2',	# ref AGND
        'stepV': '0.01',	# step volt of sweeping
        'stepT': '0.05',	# hold time for each step
        'settleT': '0.05'		# time before sample
    },
    'idvt':{
        'AGND' : '2.5',	# given by the particular LDO 
        'drainV' : '1.5E-3',	# ref AGND
        'gateV' : '1.205',	#ref AGND
        'stepT' : '0.1',	# step volt of sweeping
        'settleT' : '0.05',		# time before sample
        'x_width' : '30'		# time before sample
    }
}

testParams = defaultParams
def savepara():
    f = open('config.ini','w')
    f.write(str(testParams))
    f.close()

if not os.path.isfile('config.ini'):
    savepara()
else:
    f = open('config.ini','r')
    testParams = eval(f.read())
    f.close()

'''
adc=ADS1256.ADS1256()
dac=DAC8532.DAC8532()
adc.ADS1256_init()

if DAC8532.DAC_VREF!=5:
    DAC8532.DAC_VREF=5.18
    print(f'DAC Vref set to 5.18 V')

def Output(channel,volt,dac=dac):
    volt=volt * 5.0/ 5.188# Calibration

    if channel==1: #channel 0 or channel 1
        dac.DAC8532_Out_Voltage(0x34,volt)
    else:
        dac.DAC8532_Out_Voltage(0x30,volt)
'''
# measure Id while sweeping Vg

print('Data Collection Server Start!')
print('---------------------------')

import asyncio
import websockets

#记录服务器运行状态，等待waiting，运行running，暂停paused，停止stopped
serverStatus = {'stat':'waiting','msg':''} 

async def sendmessage(websocket,msg,type='text'):
    resp = {}
    resp["type"] = type
    resp["value"] = msg
    await websocket.send(json.dumps(resp))

async def mainthread(websocket):
    import numpy as np
    import asyncio
    
    global serverStatus
    global adc
    global Output
    
    while True:
        message = ''
        while True:
            await asyncio.sleep(0.05)
            if serverStatus['stat'] == 'running':
                message = serverStatus['msg']
                break        
        if message == '#collect':
            await sendmessage(websocket,localIp)
            #***************Var Decl. and Init.**************
            AGND = eval(testParams['trans']['AGND'])	# given by the particular LDO 
            drainV = eval(testParams['trans']['drainV'])	# ref AGND
            gateV_begin = eval(testParams['trans']['gateV_begin'])	# ref AGND 
            gateV_end = eval(testParams['trans']['gateV_end'])	# ref AGND
            stepV = eval(testParams['trans']['stepV'])	# step volt of sweeping
            stepT = eval(testParams['trans']['stepT'])	# hold time for each step
            settleT = eval(testParams['trans']['settleT'])		# time before sample
            pinNum_drain = 1	# DAC pinNum giving drainV
            pinNum_source = 0	# ADC pinNum sensing osc 
            pinNum_gate = 0	# DAC pinNum giving gateV
            pinNum_AGND = 1	# ADC pinNum recaliber AGND
            is_sweep_reverse = 0
            do_abs_Id = False
            Vcc = 5
            kR = 1E6

            vd = drainV + AGND
            vg = gateV_begin + AGND
            ftSettle = settleT
            ftHold = stepT
            vmax = gateV_end - gateV_begin
            n = int(vmax / stepV)	#num of samp
            
            rs=[]
            X=[]
            cur_AGND=[]
            Id=[]
            Vg=[]
                    
            #***************Sweep Back**************
            if is_sweep_reverse:
                gateV_begin, gateV_end = gateV_end, gateV_begin
            
            #serv est and basic func
            '''
            Output(pinNum_gate, vg)
            Output(pinNum_drain, vd)
            '''
            #***************AGND Pre-sampling**************
            '''
            preAGND = []
            nPreset = int(ftSettle / ftHold)
            for i in range(nPreset):
                r = adc.ADS1256_GetAll()
                preAGND.append(r[pinNum_AGND] * Vcc / 0x7fffff)
                await asyncio.sleep(ftHold)
            
            averAGND = np.mean(preAGND)
            AGND = averAGND
            vd = drainV + AGND
            vg = gateV_begin + AGND
            Output(pinNum_gate, vg)
            Output(pinNum_drain, vd)
            await asyncio.sleep(ftSettle)
            
            lastAGND = AGND
            '''
            for i in range(n):
                if serverStatus['stat'] == 'stopped':
                    serverStatus['stat'] = 'waiting'
                    break
                '''                
                Output(pinNum_drain, drainV + lastAGND)
                Output(pinNum_gate, i * vmax / n + vg)
                '''
                X.append(i * vmax / n + gateV_begin)
                '''
                r=adc.ADS1256_GetAll()
                rs.append(r[pinNum_source] * Vcc / 0x7fffff)
                Vg.append(r[7] * Vcc / 0x7fffff - AGND)
                cur_AGND.append(r[pinNum_AGND] * Vcc / 0x7fffff)
                lastAGND = cur_AGND[-1]
                '''
                await asyncio.sleep(ftHold)
                '''
                Id.append((rs[-1] - cur_AGND[-1])*10)
                '''
                resp = {}
                resp["type"] = "data"
                resp["value"] = "[{}, {:.4f}]".format(X[-1],random.random())
                await websocket.send(json.dumps(resp))
                if serverStatus['stat'] == 'paused':
                    while True:
                        await asyncio.sleep(0.05)
                        if serverStatus['stat'] == 'running':
                            break
                        if serverStatus['stat'] == 'stopped':
                            serverStatus['stat'] == 'waiting'
                            break
            #***************Voltage Reset**************
            #await asyncio.sleep(ftSettle)
            #Output(pinNum_drain, 2.5)
            #Output(pinNum_gate, 2.5)
            await asyncio.sleep(ftSettle)
            serverStatus['stat'] = 'waiting'  
        elif message == '#idvt':
            await sendmessage(websocket,localIp)
            #***************Var Decl. and Init.**************
            AGND = eval(testParams['idvt']['AGND'])	# given by the particular LDO 
            drainV = eval(testParams['idvt']['drainV'])	# ref AGND
            gateV = eval(testParams['idvt']['gateV'])	#ref AGND

            stepT = eval(testParams['idvt']['stepT'])	# step volt of sweeping
            settleT = eval(testParams['idvt']['settleT'])		# time before sample
            pinNum_drain = 1	# DAC pinNum giving drainV
            pinNum_source = 0	# ADC pinNum sensing osc 
            pinNum_gate = 0	# DAC pinNum giving gateV
            pinNum_AGND = 1	# ADC pinNum recaliber AGND
            Vcc = 5
            kR = 1E6
            
            vd = drainV + AGND	#drain volt. used for Pi output
            vg = gateV + AGND	#drain volt. used for Pi output
            ftSettle = settleT
            ftHold = stepT
            
            #***************Save**************
            #filename = "/home/pi/Desktop/Pi Test_GYF_ZYY_YHT/2022-02-14/data.txt"
            #fp = open(filename, "a")
            #print(filename, file = fp)
            
            
            # =======================
            #Output(pinNum_gate, vg)
            #Output(pinNum_drain, vd)
            
            #***************AGND Pre-sampling**************
            '''
            preAGND = []
            nPreset = int(ftSettle / ftHold)
            for i in range(nPreset):
                r = adc.ADS1256_GetAll()
                preAGND.append(r[pinNum_AGND] * Vcc / 0x7fffff)
                await asyncio.sleep(ftHold)
            
            averAGND = np.mean(preAGND)	#mean of the pre-sampled AGND
            AGND = averAGND
            vd = drainV + AGND
            vg = gateV + AGND
            Output(pinNum_gate, vg)
            Output(pinNum_drain, vd)
            await asyncio.sleep(ftSettle)
            '''
            
            #***************Sampling**************
            rs=[]
            X=[]
            cur_AGND=[]
            Id=[]
            Vg=[]
            #print('Time', 'Vg', 'AGND', 'Id', sep = '\t')
            i = 0
            while True:
                if serverStatus['stat'] == 'stopped':
                    serverStatus['stat'] = 'waiting'
                    break 
                X.append(i * stepT)
                i+=1
                await asyncio.sleep(ftHold)
                '''
                Output(pinNum_gate, vg)
                r=adc.ADS1256_GetAll()
                rs.append(r[pinNum_source] * Vcc / 0x7fffff)
                cur_AGND.append(r[pinNum_AGND] * Vcc / 0x7fffff)
                
                Id.append((rs[-1] - cur_AGND[-1]))
                Vg.append(r[2] * Vcc / 0x7fffff)
                #print('%.4f'%(X[-1]), '%.8f'%(Vg[-1]), '%.8f'%(cur_AGND[-1]), '%.8f'%(Id[-1]), sep = '\t', file = fp)
                '''
                resp = {}
                resp["type"] = "idvt"
                #resp["value"] = "[{}, {:.4}]".format(X[-1],Id[-1]*1000)
                resp["value"] = "[{}, {:.4}]".format(X[-1]*1000,random.random())
                await websocket.send(json.dumps(resp))
                if serverStatus['stat'] == 'paused':
                    while True:
                        await asyncio.sleep(0)
                        if serverStatus['stat'] == 'running':
                            break
                        if serverStatus['stat'] == 'stopped':
                            serverStatus['stat'] == 'waiting'
                            break
            serverStatus['stat'] = 'waiting'  
        else:
            await sendmessage(websocket,message)
            serverStatus['stat'] = 'waiting'

async def controlthread(websocket):
    global serverStatus
    while True:
        message = await websocket.recv()
        if message == '#stop':
            serverStatus['stat'] = 'stopped'
            serverStatus['msg'] = ''
        elif message == '#pause':
            serverStatus['stat'] = 'paused'
            serverStatus['msg'] = ''
        elif message == '#continue':
            serverStatus['stat'] = 'running'
            serverStatus['msg'] = ''
        elif '#set' in message:
            global testParams
            para = message.split('|')[1]
            testParams = eval(para)
            savepara()
            await sendmessage(websocket, '参数保存成功！')
        elif message == '#default':
            testParams = defaultParams
            savepara()
            await sendmessage(websocket,testParams,'para')
            await sendmessage(websocket,'恢复默认参数！',)
        else:
            serverStatus['stat'] = 'running'
            serverStatus['msg'] = message

async def echo(websocket, path):
    await sendmessage(websocket,localIp)
    await sendmessage(websocket,testParams,'para')
    await asyncio.gather(mainthread(websocket),controlthread(websocket))

asyncio.get_event_loop().run_until_complete(websockets.serve(echo, '0.0.0.0', 9575))
asyncio.get_event_loop().run_forever()

